package com.yupi.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;

import com.google.gson.reflect.TypeToken;
import com.yupi.usercenter.commons.ErrorCode;
import com.yupi.usercenter.exception.BusinessException;
import com.yupi.usercenter.pojo.Users;
import com.yupi.usercenter.service.UsersService;
import com.yupi.usercenter.mapper.UsersMapper;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.description.method.MethodDescription;
import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.yupi.usercenter.constant.UserConstant.USER_LOGIN_STATE;

/**
 * @author mxs
 */
@Service
@Slf4j
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users>
        implements UsersService {

    @Resource
    private UsersMapper usersMapper;

    /**
     * 盐值 加密
     */
    private static final String SALT = "yupi";

    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {
        //1.校验用户信息格式是否符合要求
        //判空,使用到了apache的commons lag包
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword, planetCode)) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "请求参数为空");
        }
        //判断账户是否小于4位
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "账户小于4位");
        }
        //判断密码是否小于8位
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "密码小于8位");

        }
        //判断用户密码和校验密码是否相同
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "两次输出密码不相同");

        }
        //使用正则表达式判断用户账号是否包其他字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern pattern = Pattern.compile(validPattern);
        if (pattern.matcher(userAccount).find()) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "账号包含其他字符");

        }
        //校验星球编号不能大于5位编号
        if (planetCode.length() > 5) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "星球编号大于5位");

        }

        //判断该用户名字是否已经存在
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        if (this.count(queryWrapper) < 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "该账户的名称已经存在");

        }

        //星球编号不能重复
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("planetCode", planetCode);
        if (this.count(queryWrapper) > 0) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "该星球编号已经注册");

        }

        //2.加密密码

        //加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        //3.向数据库插入数据
        Users users = new Users();
        users.setUserAccount(userAccount);
        users.setUserPassword(encryptPassword);
        users.setPlanetCode(planetCode);
        boolean result = this.save(users);
        if (!result) {
            throw new BusinessException(ErrorCode.SAVE_ERROR, "注册失败");

        }

        return users.getId();
    }

    @Override
    public Users userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        //1.判断用户的信息格式是否正确
        //判空
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.NO_LOGIN, "用户信息部分为空");

        }
        //判断账号是否小于4位
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.NO_LOGIN, "用户账户小于4位");
        }
        //判断用户账号是否大于512 防止用户上传几个G的用户账户导致崩溃
        if (userAccount.length() > 512) {
            throw new BusinessException(ErrorCode.NO_LOGIN, "用户账户过长");
        }
        //判断用户的密码是否小于8位
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.NO_LOGIN,"用户密码小于4位");

        }
        //给用户名是否包含非法字符

        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern pattern = Pattern.compile(validPattern);
        if (pattern.matcher(userAccount).find()) {
            return null;
        }

        //密码加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());

        //2.判断用户用户名和密码是否匹配
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        queryWrapper.eq("userPassword", encryptPassword);
        Users user = this.getOne(queryWrapper);
        if (null == user) {
            log.info("user login failed ,userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.LOGIN_USERNAME_OR_PWD_ERROR, "用户名或者密码错误");
        }
        //3.用户信息脱敏（将敏感的信息去掉）
        Users safetyUser = getSafetyUser(user);

        //4.将用户脱敏后的信息放到session中
        request.getSession().setAttribute(USER_LOGIN_STATE, user);
        request.getSession().getAttribute(USER_LOGIN_STATE);

        //5.返回用户
        return safetyUser;
    }

    @Override
    public int userLogout(HttpServletRequest request) {
        //移除用户态
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return 1;
    }

    /**
     * 用户脱敏
     *
     * @param originUser 原始用户
     * @return 返回脱敏后的用户信息
     */
    @Override
    public Users getSafetyUser(Users originUser) {
        //判断用户是否为空
        if (null == originUser) {
            return null;
        }
        Users safetyUser = new Users();
        safetyUser.setId(originUser.getId());
        safetyUser.setUsername(originUser.getUsername());
        safetyUser.setUserAccount(originUser.getUserAccount());
        safetyUser.setAvatarUrl(originUser.getAvatarUrl());
        safetyUser.setGender(originUser.getGender());
        safetyUser.setPhone(originUser.getPhone());
        safetyUser.setEmail(originUser.getEmail());
        safetyUser.setUserStatus(originUser.getUserStatus());
        safetyUser.setCreateTime(originUser.getCreateTime());
        safetyUser.setRole(originUser.getRole());
        safetyUser.setPlanetCode(originUser.getPlanetCode());
        safetyUser.setTags(originUser.getTags());
        return safetyUser;
    }

    /**
     * 根据标签名查找用户
     * 内存计算
     *
     * @param tagNameList  标签列表
     * @return user list
     */
    @Override
    public List<Users> searchUsersByTagsByCached(List<String> tagNameList){
        //判空
        if (CollectionUtils.isEmpty(tagNameList)){
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }

        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        //查询
        List<Users> userList = usersMapper.selectList(queryWrapper);

        userList = userList.stream().filter(users -> {
            //获取用户的tags
            String tagJson = users.getTags();
            //解析json对象
            Gson gson = new Gson();
            Set<String> tempUserTagSet = gson.fromJson(tagJson,new TypeToken<Set<String>>(){}.getType());
            if (tempUserTagSet == null){
                return false;
            }
            return tempUserTagSet.containsAll(tagNameList);
        }).collect(Collectors.toList());


        //脱敏
        return userList.stream().map(this::getSafetyUser).collect(Collectors.toList());
    }

    /**
     * 根据标签名查找用户
     * 数据库计算
     *
     * @param tagNameList  标签列表
     * @return user list
     */
    @Override
    public List<Users> searchUsersByTagsByDB(List<String> tagNameList) {

        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();

        for (String tagName : tagNameList) {
            queryWrapper.like("tags",tagName);
        }

        return usersMapper.selectList(queryWrapper).stream().map(this::getSafetyUser).collect(Collectors.toList());


    }
}




